//
//  HttpClient.swift
//  BaoDan
//
//  Created by 郭子龙 on 2025/4/2.
//

import Foundation
import ProgressHUD

/// 网络请求错误枚举
enum NetworkError: Error {
  case invalidURL
  case noData
  case decodingError
  case serverError(Int)
  case customError(String)
}

/// 通用响应结构体
struct Response<T: Decodable>: Decodable {
  let code: Int
  let message: String
  let data: T
  let serverIp: String
  let time: Int64
}

/// 只解析最基础的 Response，不关心 data 内容
private struct ResponseWithoutData: Decodable {
  let code: Int
  let message: String
}

/// 网络请求客户端
class HttpClient {
  /// 单例模式
  static let shared = HttpClient()

  /// URLSession实例
  private let session: URLSession

  /// 基础URL
  private let baseURL = "https://bdw.zmeng123.com/kb/app"

  private var authToken: String? {
    return UserDefaults.baodan.string(forKey: UserDefaults.tokenKey)  // 或从其他地方获取
  }

  /// 私有初始化方法
  private init() {
    let config = URLSessionConfiguration.default
    config.timeoutIntervalForRequest = 30
    self.session = URLSession(configuration: config)
  }

  private func createRequest(endpoint: String, method: String = "GET", body: Data? = nil)
    -> URLRequest?
  {
    guard let url = URL(string: baseURL + endpoint) else { return nil }
    var request = URLRequest(url: url)

    // 设置请求方法
    request.httpMethod = method

    // 设置 Authorization header
    if let token = authToken {
      request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")  // 这里我们使用 Bearer token
    }

    // 如果是 POST 请求，添加请求体
    if let body = body {
      request.httpBody = body
      request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    }

    return request
  }

  /// 发送GET请求
  /// - Parameters:
  ///   - endpoint: API端点
  ///   - parameters: URL参数
  ///   - completion: 完成回调
  func get<T: Decodable>(
    endpoint: String,
    parameters: [String: Any]? = nil,
    completion: @escaping (Result<T, NetworkError>) -> Void
  ) {
    guard let url = buildURL(endpoint: endpoint, parameters: parameters) else {
      completion(.failure(.invalidURL))
      return
    }

    let task = session.dataTask(with: url) { data, response, error in
      self.handleResponse(data: data, response: response, error: error, completion: completion)
    }
    task.resume()
  }

  /// 发送POST请求
  /// - Parameters:
  ///   - endpoint: API端点
  ///   - body: 请求体
  ///   - completion: 完成回调
  func post<T: Decodable>(
    endpoint: String,
    body: [String: Any],
    completion: @escaping (Result<T, NetworkError>) -> Void
  ) {
    guard let url = buildURL(endpoint: endpoint) else {
      completion(.failure(.invalidURL))
      return
    }

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    // 设置 Authorization header   F
    if let token = authToken {
      request.setValue("\(token)", forHTTPHeaderField: "auth_token")  // 这里我们使用 Bearer token
    }

    do {
      request.httpBody = try JSONSerialization.data(withJSONObject: body)
    } catch {
      completion(.failure(.customError("Invalid request body")))
      return
    }

    let task = session.dataTask(with: request) { data, response, error in
      self.handleResponse(data: data, response: response, error: error, completion: completion)
    }
    task.resume()
  }

  func postWithAutoHUD<T: Decodable>(
    endpoint: String,
    body: [String: Any],
    showHUD: Bool = true,
    completion: @escaping (Result<T, String>) -> Void
  ) {
    self.post(endpoint: endpoint, body: body) { (result: Result<T, NetworkError>) in
      DispatchQueue.main.async {
        switch result {
        case .success(let data):
          completion(.success(data))

        case .failure(let error):
          let message: String
          switch error {
          case .serverError(let code):
            message = "服务器错误: \(code)"
          case .noData:
            message = "未收到服务器响应"
          case .decodingError:
            message = "数据解析错误"
          case .invalidURL:
            message = "无效的URL"
          case .customError(let msg):
            message = msg
          }

          if showHUD {
            ProgressHUD.failed(message)
          }
          completion(.failure(message))
        }
      }
    }
  }

  // 返回T
  func postWithAutoHUD<T: Decodable>(
    endpoint: String,
    body: [String: Any],
    showHUD: Bool = true,
    completion: @escaping (T?) -> Void
  ) {
    self.post(endpoint: endpoint, body: body) { (result: Result<T, NetworkError>) in
      DispatchQueue.main.async {
        switch result {
        case .success(let data):
          completion(data)

        case .failure(let error):
          if showHUD {
            let message: String
            switch error {
            case .serverError(let code):
              message = "服务器错误: \(code)"
            case .noData:
              message = "未收到服务器响应"
            case .decodingError:
              message = "数据解析错误"
            case .invalidURL:
              message = "无效的URL"
            case .customError(let msg):
              message = msg
            }
            ProgressHUD.failed(message)
          }
          completion(nil)
        }
      }
    }
  }

  /// 构建URL
  /// - Parameters:
  ///   - endpoint: API端点
  ///   - parameters: URL参数
  /// - Returns: 构建好的URL
  private func buildURL(endpoint: String, parameters: [String: Any]? = nil) -> URL? {
    var urlString = baseURL + endpoint

    if let parameters = parameters {
      let queryItems = parameters.map { key, value in
        return "\(key)=\(value)"
      }.joined(separator: "&")
      urlString += "?" + queryItems
    }

    return URL(string: urlString)
  }

  /// 处理响应数据
  /// - Parameters:
  ///   - data: 响应数据
  ///   - response: 响应对象
  ///   - error: 错误信息
  ///   - completion: 完成回调
  private func handleResponse<T: Decodable>(
    data: Data?,
    response: URLResponse?,
    error: Error?,
    completion: @escaping (Result<T, NetworkError>) -> Void
  ) {
    if let error = error {
      completion(.failure(.customError(error.localizedDescription)))
      return
    }

    guard let httpResponse = response as? HTTPURLResponse else {
      completion(.failure(.customError("Invalid response")))
      return
    }

    guard (200...299).contains(httpResponse.statusCode) else {
      completion(.failure(.serverError(httpResponse.statusCode)))
      return
    }

    guard let data = data else {
      completion(.failure(.noData))
      return
    }

    if let jsonString = String(data: data, encoding: .utf8) {
      print("Raw JSON data: \(jsonString)")
    }

    do {
      let decoder = JSONDecoder()
      // 第一次，先解成不带泛型的Response
      let baseResponse = try decoder.decode(ResponseWithoutData.self, from: data)

      guard baseResponse.code == 0 else {
        completion(.failure(.customError(baseResponse.message)))
        return
      }

      // 业务成功，再去解带T的 Response
      let result = try decoder.decode(Response<T>.self, from: data)
      completion(.success(result.data))

    } catch let decodeError as DecodingError {
      switch decodeError {
      case .typeMismatch(let type, let context):
        print("❌ Type mismatch: \(type), Context: \(context.debugDescription)")
      case .keyNotFound(let key, let context):
        print("❌ Key not found: \(key), Context: \(context.debugDescription)")
      case .valueNotFound(let type, let context):
        print("❌ Value not found: \(type), Context: \(context.debugDescription)")
      case .dataCorrupted(let context):
        print("❌ Data corrupted: \(context.debugDescription)")
      default:
        print("❌ Decoding error: \(decodeError)")
      }
      completion(.failure(.decodingError))
    } catch {
      completion(.failure(.decodingError))
    }
  }
}
